X Ŀ B
 O ͻ P
 R  .    .Ŀ .    *    Ŀ Ŀ   . Ŀ  .    *Ŀ   .     * X
ٺ               .۳                     Ŀ
ͼ   * Ŀ    .    ۳ .    Ŀ۳    .  ڿ۳.     .  ͻ
 . Ŀ ۳  Ŀ     Ŀ.. Ŀ ۳ Ŀ Ŀ.
  ۳۳  ۳* .۳*  ۳ ۳*   ۳. ۳ 
 ٳ ۳Ŀ ڿ   Ŀ  ۳  
*. ٳ ۳۳. Ŀ ۳  ڿ..  
 ۳   . ۳  ۳۳ٳ۳   ۳۳ ۳    
        ۳ ٳ۳ .   ڿ   
 Ŀ*       .  .    *  ۳ *      Ŀ     *  ۳* 
. ۳   .                 ۳       . ۳  .     ۳ 
              .              .              ..
members:       *    .       *  members: .            *     .       members:
 *    beanus   dulek      jaro   massh    mig-21 oxcart  zetx
arakus .  coxoc   hannibal  lobix * mauzer    neo  ._r00t_  
ٺ
ͻ   .        .           *     .         .           *   ĿĿĿĿ ͼ
Ŀ official URL: http://beanus.provider.pl/     .         ٳ۳۳۳ 
 E  *     on IRC: #crackpl or #cookiecrk  *          .       C
 X ͼ M
 P  P

Cel: Duelist`s CM #3
Narzedzia: Wdasm 8.x, Tasm 5.0, eXeScope 5.0 - opcjonalnie SoftIce 4.x, Hiew 6.x

[Ogledziny]
-

[Sekcja]
Odpalamy crackme. Zadnych Anty-SI nie widac. Zauwazamy (trudno nie zauwazyc) w oknie dialogowym
tekst : "Tip : You should use a resource editor!". Ok, wiec siegamy po jakis edytor zasobow - ja
skozystalem z eXeScope`a 5.0. Otwieramy nasze crackme i przechodzimy na interesujace nas okno 
dialogowe. Co tu moze byc ciekawego ? Of coz nic innego jak ID odpowiednich checkboxow. Przeglodamy
checkbox`y i spisujemy wartosci ID :

		97 | 73 | 94 | 22 | 37 | 38 | 33 | 89 | 83
		------------------------------------------
		21 | 55 | 49 | 72 | 93 | 12 | 82 | 39 | 29

Nastepnie dissasemblujemy crackme w poszukiwaniu funkcji odpowiedzialnych za checkboxy. Znajdujemy
funkcje IsDlgButtonChecked. Z Win32 Programmer's Reference wynika jasno :

Funkcja ta sprawdza stan przycisku o okreslonym identyfikatorze i dla danego okna dialogowego 
okreslonego uchwytem.

	UINT IsDlgButtonChecked(
    		HWND hDlg,		// handle of dialog box
    		int nIDButton	// button identifier
   	);

gdzie :

hDlg - uchwyt okna dialogowego. 

nIDButton - ID sprawdzanego przycisku.

Jezeli przycisk o danym ID jest zaznaczony funkcja zwroci wartosc 1, jezeli nie to 0.

Powyzsza funkcje mozemy znalezc w inny sposob, a mianowicie szukajac procedury zarzadzajacej
zdazeniami (nacisniecie przycisku itp.). Znajdujemy DefWindowProcA, a poznizej :

:004010CE C8000000                enter 0000, 00
:004010D2 53                      push ebx
:004010D3 56                      push esi
:004010D4 57                      push edi
:004010D5 817D0C11010000          cmp dword ptr [ebp+0C], 00000111 <-- WM_COMMAND
:004010DC 0F84CF000000            je 004011B1
:004010E2 817D0C10010000          cmp dword ptr [ebp+0C], 00000110
:004010E9 7416                    je 00401101
:004010EB 837D0C10                cmp dword ptr [ebp+0C], 00000010
:004010EF 0F84CC000000            je 004011C1
:004010F5 B800000000              mov eax, 00000000

<...>

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004010DC(C)
|
:004011B1 837D1001                cmp dword ptr [ebp+10], 00000001 <--- Czy nacisnieto przycisk "Check" ?
:004011B5 0F845CFFFFFF            je 00401117
:004011BB 837D1002                cmp dword ptr [ebp+10], 00000002 <--- przycisk "Close"
:004011BF 750F                    jne 004011D0


Tak wiec pod adresem xxx:401117 zaczyna sie wlasciwa procedura sprawdzajaca poprawnosc zaznaczonych 
przyciskow i generujaca na tej podstawie komunikat etc. Bad/Good. :



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004011B5(C)
|
:00401117 33F6                    xor esi, esi <--- na poczatku esi=0
:00401119 33D2                    xor edx, edx
:0040111B 89355E214000            mov dword ptr [0040215E], esi
:00401121 893562214000            mov dword ptr [00402162], esi

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00401146(C), :00401160(U)
|
:00401127 0FBE8EFE204000          movsx ecx, byte ptr [esi+004020FE]
:0040112E 83F94D                  cmp ecx, 0000004D <--- juz koniec ?
:00401131 742F                    je 00401162 <--- tak, to sprawdz wartosc
:00401133 890D5E214000            mov dword ptr [0040215E], ecx
:00401139 51                      push ecx
:0040113A FF7508                  push [ebp+08]

* Reference To: USER32.IsDlgButtonChecked, Ord:0000h
                                  |
:0040113D E8D0010000              Call 00401312
:00401142 46                      inc esi
:00401143 83F800                  cmp eax, 00000000 <--- zaznaczone odpowienie pole ?
:00401146 74DF                    je 00401127 <--- jezeli nie (0) to skacz
:00401148 A15E214000              mov eax, dword ptr [0040215E] <--- ID zaznaczonego przycisku
:0040114D 0FBE8EFE204000          movsx ecx, byte ptr [esi+004020FE] <--- ...
:00401154 0FAFC1                  imul eax, ecx 
:00401157 0FAFC6                  imul eax, esi
:0040115A 010562214000            add dword ptr [00402162], eax <--- dodaj
:00401160 EBC5                    jmp 00401127 <--- petla

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401131(C)
|
:00401162 A162214000              mov eax, dword ptr [00402162]
:00401167 6BC04D                  imul eax, 0000004D <--- wynik pomonoz przez 4Dh
:0040116A 3D6E8BC000              cmp eax, 00C08B6E
:0040116F 7520                    jne 00401191 <--- jezeli nie rowne Msg - BAD!
:00401171 6800200000              push 00002000
:00401176 6801204000              push 00402001
:0040117B 6817204000              push 00402017
:00401180 6A00                    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
                                  |
:00401182 E855010000              Call 004012DC
:00401187 B801000000              mov eax, 00000001
:0040118C E969FFFFFF              jmp 004010FA

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040116F(C)
|
:00401191 6800200000              push 00002000
:00401196 6801204000              push 00402001
:0040119B 6868204000              push 00402068
:004011A0 6A00                    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
                                  |
:004011A2 E835010000              Call 004012DC
:004011A7 B800000000              mov eax, 00000000
:004011AC E949FFFFFF              jmp 004010FA
  

Poczawszy od lini xxx:00401117 zaczyna sie procedura sprawdzajaca poprawnosc "wpisanego kodu" =)
Przed wejsciem do petli zerowane sa rejestry esi i edx. Nastepnie z pod adresu [esi+004020FE] do 
ecx wysylany kolejno za kazdym obiegiem petli jest 1 bajt z ciagu znajdujacego sie pod adresem
004020FE .:

	16h, 49h, 5Eh, 15h, 27h, 26h, 21h, 25h, 1Dh, 59h, 53h, 37h, 31h, 48h, 5Dh, 0Ch, 61h, 52h ,4Dh

Nie musze chyba mowic(pisac), ze po zamianie tych wartosci na decymalne otrzymujemy odpowiednie
wartosci ID naszych checkbox`ow. Pozniej wartosc pobrana porownywana jest z 4Dh - jezeli rowne to 
skocz do ostatniej (decydujacej) czesci procedury. Po prostu ... pobierane sa kolejne bajty z ciagu
przedstawionego powyzej (wartosci ID checkboxo`w), pozniej wywolywana jest funkcja majaca na celu
sprawdzenie czy zaznaczony jest dany checkbox (o okreslonym ID - ecx). Jezeli tak (eax=1) to przejdz
do czesci "obliczeniowej". Zaczyna sie ona :00401148 - :00401160 i przebiega w taki sposob :

	- przycisk od danym ID jest "wcisniety" - TAK
	- pobierz wartosc kolejnego bajtu z tego ciagu
	- przemnoz ID "wcisnietego" przycisku z ID kolejnego (kolejnego w ciagu 16h, 49h,...)
	- przemnoz ten wynik przez pozycje "wcisnietego" przycisku w tym ciagu
	- dodawaj tak kolejno wyliczone wartocsi do siebie

	- gdy pobrana z ciagu wartosc = 4Dh to skocz do ostatniej czesci - sprawdzajacej, gdzie nasza
	  suma tak przeksztalconych ID jest mnozona przez 4dh i porownywana z 0C08B6Eh

Heh "troche" zagmatwalem prosta operacje - na przykladzie wyglada to prosciej :

Zalozmy ze "wcisnelismy" przycisk o ID = 21h. Tak wiec zgodnie z tym co naskrobalem powyzej 21h 
mnozone jest przez kolejna wartosc w ciagu - 25h (21h*25h=4C5h). Teraz ten wynik jest mnozony przez
przez jego pozycje zajmowana w tym ciagu - (1,2,3...18) - 4C5h*7=2163h. Jezeli to jedyny "wcisniety"
przycisk wartosc ta bedzie przemnozona przez 4Dh i porownana z 0C08B6Eh. Natomiast jezeli to nie byl
jedyny zaznaczony checkbox to kolejne wyniki tych operacji dla checkbox`ow sa sumowane i na koncu 
mnozone przez 4Dh i porownywane ... Tak wyglada zabezpieczenie tego crackme.

[Protokol]

Jak rozwiazac te lamiglowke ? Nie inaczej niz przy uzyciu metody brute force. Wyjdzmy od tego ze 
autor crackme daje nam "w prezencie" ciag 18 bajtow (no z 4Dh to 19), ktory potraktujmy jako punkt
odniesienia. Wiemy, ze ID sa "sprawdzane" w okreslony sposob - w niezmiennej kolejnosci, co w znacznym
stopniu ulatwia nam zycie. Potraktujmy ten 18 bajtowy ciag jako 18 bitowa liczbe, w ktorej kazdy
bit moze przyjac 2 wartosci ( 0 lub 1 - of coz bo jakie inne :>. Dajne nam to 2^18 kombinacji - 40000h
- 262144 kombinacji. Cala idea programu opiera sie na dobieraniu koleno wartosci (1-3FFFFh) i  
sprawdzaniu ktore bity sa zapalone (1). Zapalone bity beda symbolizowac odpowiednie "wcisniete" 
przyciski i dla takiej kombinacji przyciskow bedzie liczona cala procedura.
No i znowu przyklad.:

000000000000000110 = 6 -> "wcisniete" sa przyciski o ID 49h i 5Eh i dla nich przeliczamy procedure itd.

Ok dla leniwych zrodlo :

[start]

.razem z archiwum.

[end] 

Nie jest to zrodlo najwyzszych lotow, ale spelnia swoje zadanie w 100 %. Tak wiec po kompilacji,
uruchomieniu i zastawieniu plapki na MessageBoxA w rejestrze EBX znajduje sie poprawna wartosc = 1CEDh

1CEDh = 000001110011101101 -> 101101110011100000 -> 16h, 5Eh, 15h, 26h, 21h, 25h, 53h, 37h, 31h

 
     	|   |   | X | X | X | X | X |   | X | 
    	-------------------------------------
     	| X | X | X |   |   |   |   |   |   |


Fin.
____________________________________________________________________________________________________
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Greetz: CookieCrK & #crackpl

     r00t^CookieCrK

   mail:r00t@polbox.com

website: www.cookiecrk.z.pl

